package fun.yao.common.db;

import fun.yao.common.Constant;
import fun.yao.common.security.DESede;
import fun.yao.common.security.SSLConstant;
import fun.yao.common.uitls.ConfigUtil;
import fun.yao.common.uitls.LogUtil;

import java.sql.Connection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 连接池管理类
 */
public class ConnManager {

    /** 当前数据库连接池 */
    protected static ConnPool currPool = null ;

    /** 历史数据库连接池 */
    protected static ConnPool hisPool = null ;

    public static Map<String,ConnPool> htPool = new ConcurrentHashMap<String, ConnPool>();

    /** 构造函数 */
    public ConnManager()
    {

    }

    /**
     * 功能描述：初始化数据库连接
     * 如果vDataSouces为null，则初始化当前数据库连接
     * @author longjinglai
     * @date 2018/12/18 16:25
     * @param vDataSouces  数据源数组
     * @return void
     * @Exception
     **/
    public static void initPool(String... vDataSouces) throws Exception {
        if (vDataSouces == null) {
            initCurrPool();
        } else {
            for (String dataSouce : vDataSouces) {
                if (dataSouce != null) {
                    initPool(dataSouce);
                }
            }
        }
    }

    /**
     * 功能描述：初始化数据库连接池
     *
     * @author longjinglai
     * @date 2019/1/23 16:56
     * @param connProperties
     * @return void
     * @Exception
     **/
    public static void initPool(ConnProperties connProperties) throws Exception {
        if(htPool.containsKey(connProperties.getDataSourceName()))
            return;
        ConnPool pool = new ConnPool();

        pool = new ConnPool();
        pool.setName("ConnPool-"+connProperties.getDataSourceName());
        pool.setDbType(ConnPool.CONN_POOL_TYPE_CURR);
        pool.setJdbcInfo(connProperties.getDbDriver(), connProperties.getDbUrl(), connProperties.getDbUserName(), decryptDbPassward(connProperties.getDbPwd()));
        pool.setPoolSize(connProperties.getPoolSize());
        pool.setTestSql(connProperties.getTestSql());
        pool.setSqlTestInvTime(connProperties.getSqlTestInvTime());
        pool.setConnOverTime(connProperties.getConnOverTime());
        pool.setGetWaitTime(connProperties.getGetWaiteTime());
        testLinkDb(pool);

        pool.start();
        htPool.put(connProperties.getDataSourceName(), pool);

        if(connProperties.getDataSourceName().equals("Curr")){
            currPool = pool;
        }else if(connProperties.getDataSourceName().equals("His")){
            hisPool = pool;
        }

        Thread.sleep(3000);
    }

    /**
     * 根据数据源初始化数据库连接池
     * @param vDataSource 数据源名称
     * @throws Exception
     */
    public static void initPool(String vDataSource) throws Exception
    {
        if(htPool.containsKey(vDataSource))
            return;

        int    iPoolSize = ConfigUtil.getConfigByInt("DB_MAX_CONNECTION_"+vDataSource,5);
        String sDbDriver = ConfigUtil.getConfigByString("DB_DRIVER_"+vDataSource,"oracle.jdbc.driver.OracleDriver");
        String sDbUrl    = ConfigUtil.getConfigByString("DB_URL_"+vDataSource,"");
        String sDbUid    = ConfigUtil.getConfigByString("DB_USER_"+vDataSource,"");
        String sDbPwd    = ConfigUtil.getConfigByString("DB_PASSWORD_"+vDataSource,"");
        String sTestSql  = ConfigUtil.getConfigByString("DB_TEST_SQL_"+vDataSource,"select * from dual");
        int    iSqlTestInvTime = ConfigUtil.getConfigByInt("DB_TEST_INV_TIME_"+vDataSource, 60);
        int    iConnOverTime   = ConfigUtil.getConfigByInt("DB_CONN_OVERTIME_"+vDataSource, 4*60*60);
        int    iGetWaitTime    = ConfigUtil.getConfigByInt("DB_CONN_GET_WAITTIME_"+vDataSource, 2*60);
        ConnPool pool = new ConnPool();

        pool = new ConnPool();
        pool.setName("ConnPool-"+vDataSource);
        pool.setDbType(ConnPool.CONN_POOL_TYPE_CURR);
        pool.setJdbcInfo(sDbDriver, sDbUrl, sDbUid, decryptDbPassward(sDbPwd));
        pool.setPoolSize(iPoolSize);
        pool.setTestSql(sTestSql);
        pool.setSqlTestInvTime(iSqlTestInvTime);
        pool.setConnOverTime(iConnOverTime);
        pool.setGetWaitTime(iGetWaitTime);
        testLinkDb(pool);

        pool.start();
        htPool.put(vDataSource, pool);

        Thread.sleep(3000);
    }

    /** 初始化当前数据库连接池 */
    public static void initCurrPool() throws Exception
    {
        if (htPool.containsKey("Curr")) {
            return;
        }

        int    iPoolSize = ConfigUtil.getConfigByInt("DB_MAX_CONNECTION",5);
        String sDbDriver = ConfigUtil.getConfigByString("DB_DRIVER","oracle.jdbc.driver.OracleDriver");
        String sDbUrl    = ConfigUtil.getConfigByString("DB_URL","");
        String sDbUid    = ConfigUtil.getConfigByString("DB_USER","");
        String sDbPwd    = ConfigUtil.getConfigByString("DB_PASSWORD","");
        String sTestSql  = ConfigUtil.getConfigByString("DB_TEST_SQL","select * from dual");
        int    iSqlTestInvTime = ConfigUtil.getConfigByInt("DB_TEST_INV_TIME", 60);
        int    iConnOverTime   = ConfigUtil.getConfigByInt("DB_CONN_OVERTIME", 4*60*60);
        int    iGetWaitTime    = ConfigUtil.getConfigByInt("DB_CONN_GET_WAITTIME", 2*60);

        currPool = new ConnPool();
        currPool.setName("ConnPool-Curr");
        currPool.setDbType(ConnPool.CONN_POOL_TYPE_CURR);
        currPool.setJdbcInfo(sDbDriver, sDbUrl, sDbUid, decryptDbPassward(sDbPwd));
        currPool.setPoolSize(iPoolSize);
        currPool.setTestSql(sTestSql);
        currPool.setSqlTestInvTime(iSqlTestInvTime);
        currPool.setConnOverTime(iConnOverTime);
        currPool.setGetWaitTime(iGetWaitTime);

        testLinkDb(currPool);

        currPool.start();
        htPool.put("Curr", currPool);

        Thread.sleep(3000);
    }

    /**初始化历史数据库连接池 */
    public static void initHisPool() throws Exception
    {
        int    iPoolSize = ConfigUtil.getConfigByInt("DB_MAX_CONNECTION_HIS",10);
        String sDbDriver = ConfigUtil.getConfigByString("DB_DRIVER_HIS","oracle.jdbc.driver.OracleDriver");
        String sDbUrl    = ConfigUtil.getConfigByString("DB_URL_HIS","");
        String sDbUid    = ConfigUtil.getConfigByString("DB_USER_HIS","");
        String sDbPwd    = ConfigUtil.getConfigByString("DB_PASSWORD_HIS","");
        String sTestSql  = ConfigUtil.getConfigByString("DB_TEST_SQL_HIS","select * from dual");
        int    iSqlTestInvTime = ConfigUtil.getConfigByInt("DB_TEST_INV_TIME_HIS", 60);
        int    iConnOverTime   = ConfigUtil.getConfigByInt("DB_CONN_OVERTIME_HIS", 4*60*60);
        int    iGetWaitTime    = ConfigUtil.getConfigByInt("DB_CONN_GET_WAITTIME_HIS", 2*60);

        hisPool = new ConnPool();
        hisPool.setName("ConnPool-His ");
        hisPool.setDbType(ConnPool.CONN_POOL_TYPE_HIS);
        hisPool.setJdbcInfo(sDbDriver, sDbUrl, sDbUid, decryptDbPassward(sDbPwd));
        hisPool.setPoolSize(iPoolSize);
        hisPool.setTestSql(sTestSql);
        hisPool.setSqlTestInvTime(iSqlTestInvTime);
        hisPool.setConnOverTime(iConnOverTime);
        hisPool.setGetWaitTime(iGetWaitTime);

        testLinkDb(hisPool);

        hisPool.start();
        htPool.put("His", hisPool);
        Thread.sleep(3000);

    }

    /** 检查时检查数据库连接池的配置是否正确，如果不正确终止启动 */
    protected static void testLinkDb(ConnPool pool) throws Exception
    {
        Connection dbConn = null ;
        try
        {
            dbConn = pool.buildNewConnection();
        }catch(Exception e)
        {
            LogUtil.WriteLog(Constant.BADLY_ERROR, e);
            LogUtil.WriteLog(Constant.BADLY_ERROR, "数据库连接测试失败，停止启动！");
            System.exit(1);
        }finally
        {
            if ( dbConn != null )
                dbConn.close();
        }
    }

    /**数据库密码解密*/
    protected static String decryptDbPassward(String pwd) throws Exception
    {
        //解密数据库密码
        byte[] pwdBytes = DESede.base64DecodeToBytes(pwd);
        return new String(DESede.decrypt(SSLConstant.DEFAULT_KEY.getBytes(), SSLConstant.DEFAULT_DESEDE_IV.getBytes(), pwdBytes));
    }

    //-------------------------------------------------------------------------
    /** 从当前数据库连接池中获取新的连接 */
    public static Connection getConnByCurr() throws Exception
    {
        return currPool.getConn() ;
    }

    public static Connection getConnByCurr(boolean autoCommit) throws Exception
    {
        return currPool.getConn(autoCommit) ;
    }

    /** 从当前数据库连接池中获取新的连接 */
    public static Connection getConnByCurr(int iWaitTime) throws Exception
    {
        return currPool.getConn(iWaitTime) ;
    }

    public static Connection getConnByCurr(int iWaitTime,boolean autoCommit) throws Exception
    {
        return currPool.getConn(iWaitTime,autoCommit) ;
    }

    /** 在当前数据库中创建新连接 */
    public static Connection buildNewConnectionByCurr() throws Exception
    {
        return currPool.buildNewConnection();
    }

    public static Connection buildNewConnectionByCurr(boolean autoCommit) throws Exception
    {
        return currPool.buildNewConnection(autoCommit);
    }

    /** 关闭当前数据库连接池 */
    public static void closeByCurr()
    {
        currPool.close();
    }

    //-------------------------------------------------------------------------
    /** 从历史数据库连接池中获取新的连接 */
    public static Connection getConnByHis() throws Exception
    {
        return hisPool.getConn() ;
    }

    public static Connection getConnByHis(boolean autoCommit) throws Exception
    {
        return hisPool.getConn(autoCommit) ;
    }

    /** 从历史数据库连接池中获取新的连接 */
    public static Connection getConnByHis(int iWaitTime) throws Exception
    {
        return hisPool.getConn(iWaitTime) ;
    }

    public static Connection getConnByHis(int iWaitTime,boolean autoCommit) throws Exception
    {
        return hisPool.getConn(iWaitTime,autoCommit) ;
    }

    /** 在历史数据库中创建新连接 */
    public static Connection buildNewConnectionByHis() throws Exception
    {
        return hisPool.buildNewConnection();
    }

    public static Connection buildNewConnectionByHis(boolean autoCommit) throws Exception
    {
        return hisPool.buildNewConnection(autoCommit);
    }

    /** 关闭当前数据库连接池 */
    public static void closeByHis()
    {
        hisPool.close();
    }

    //-------------------------------------------------------------------------
    /** 通用的数据库连接释放 */
    public static void freeConn(Connection dbConn )
    {
        GessConnection gessConn = (GessConnection)dbConn ;
        gessConn.getConnPool().freeConn(gessConn);
    }

    /**
     * 获取数据连接
     * @param vDataSource 数据源名称
     * @return
     * @throws Exception
     */
    public static Connection getConn(String vDataSource) throws Exception
    {
        if(htPool.containsKey(vDataSource))
        {
            return htPool.get(vDataSource).getConn();
        }else
        {
            return null;
        }
    }

    public static Connection getConn(String vDataSource,boolean autoCommit) throws Exception
    {
        if(htPool.containsKey(vDataSource))
        {
            return htPool.get(vDataSource).getConn(autoCommit);
        }else
        {
            return null;
        }
    }

    /**
     * 获取数据库连接
     * @param vDataSource 数据源名称
     * @param iWaitTime 等待时间
     * @return
     * @throws Exception
     */
    public static Connection getConn(String vDataSource,int iWaitTime) throws Exception
    {
        if(htPool.containsKey(vDataSource))
        {
            return htPool.get(vDataSource).getConn(iWaitTime);
        }else
        {
            return null;
        }
    }

    public static Connection getConn(String vDataSource,int iWaitTime,boolean autoCommit) throws Exception
    {
        if(htPool.containsKey(vDataSource))
        {
            return htPool.get(vDataSource).getConn(iWaitTime,autoCommit);
        }else
        {
            return null;
        }
    }

    /**
     * 新建数据库连接
     * @param vDataSource 数据源名称
     * @return
     * @throws Exception
     */
    public static Connection buildNewConnection(String vDataSource) throws Exception
    {
        if(htPool.containsKey(vDataSource))
        {
            return htPool.get(vDataSource).buildNewConnection();
        }else
        {
            return null;
        }
    }

    public static Connection buildNewConnection(String vDataSource,boolean autoCommit) throws Exception
    {
        if(htPool.containsKey(vDataSource))
        {
            return htPool.get(vDataSource).buildNewConnection(autoCommit);
        }else
        {
            return null;
        }
    }

    /**
     * 关闭连接池
     * @param vDataSource 数据源名称
     */
    public static void closePool(String vDataSource)
    {
        if(htPool.containsKey(vDataSource))
        {
            htPool.get(vDataSource).close();
        }
    }

}

